import json
import logging
from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from django.contrib.auth.models import AnonymousUser
from .models import User, PrivateMessage, ChatGroup, GroupMessage, MessageReadStatus

logger = logging.getLogger(__name__)


class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        try:
            self.user = self.scope["user"]

            if isinstance(self.user, AnonymousUser):
                logger.warning("匿名用户尝试连接 WebSocket，已拒绝")
                await self.close()
                return

            # 为用户创建个人频道
            self.user_channel = f"user_{self.user.id}"
            await self.channel_layer.group_add(
                self.user_channel,
                self.channel_name
            )

            # 加入用户所在的群组
            user_groups = await self.get_user_groups()
            for group in user_groups:
                group_channel = f"group_{group.id}"
                await self.channel_layer.group_add(
                    group_channel,
                    self.channel_name
                )

            # 加入在线用户组
            await self.channel_layer.group_add(
                "online_users",
                self.channel_name
            )

            await self.accept()

            # 发送连接成功消息
            await self.send(text_data=json.dumps({
                'type': 'connection_established',
                'message': 'WebSocket连接成功'
            }))

            logger.info(f"用户 {self.user.id} WebSocket 连接成功")

        except Exception as e:
            logger.error(f"WebSocket连接异常: {e}")
            await self.close()

    async def disconnect(self, close_code):
        logger.info(f"WebSocket 断开: 用户 {getattr(self.user, 'id', 'Anonymous')}, 代码: {close_code}")

        try:
            if hasattr(self, 'user_channel'):
                await self.channel_layer.group_discard(
                    self.user_channel,
                    self.channel_name
                )

                # 离开用户所在的群组
                user_groups = await self.get_user_groups()
                for group in user_groups:
                    group_channel = f"group_{group.id}"
                    await self.channel_layer.group_discard(
                        group_channel,
                        self.channel_name
                    )

                # 离开在线用户组
                await self.channel_layer.group_discard(
                    "online_users",
                    self.channel_name
                )
        except Exception as e:
            logger.error(f"WebSocket断开清理异常: {e}")

    async def receive(self, text_data):
        try:
            data = json.loads(text_data)
            message_type = data.get('type')

            logger.info(f"收到 WebSocket 消息: {message_type}, 用户: {self.user.id}")

            if message_type == 'private_message':
                await self.handle_private_message(data)
            elif message_type == 'group_message':
                await self.handle_group_message(data)
            elif message_type == 'typing':
                await self.handle_typing(data)
            elif message_type == 'read_receipt':
                await self.handle_read_receipt(data)
            elif message_type == 'auth':
                # 处理认证消息
                await self.handle_auth(data)
            else:
                logger.warning(f"未知的消息类型: {message_type}")

        except json.JSONDecodeError as e:
            logger.error(f"JSON 解析错误: {e}")
        except Exception as e:
            logger.error(f"处理消息时发生错误: {e}")

    async def handle_auth(self, data):
        """处理认证消息"""
        user_id = data.get('user_id')
        if user_id and user_id == self.user.id:
            logger.info(f"用户 {user_id} 认证成功")
            # 发送认证成功消息
            await self.send(text_data=json.dumps({
                'type': 'auth_success',
                'message': '认证成功'
            }))
        else:
            logger.warning(f"认证失败: 用户ID不匹配")

    async def handle_private_message(self, data):
        receiver_id = data.get('receiver_id')
        content = data.get('content', '').strip()

        if not content:
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '消息内容不能为空'
            }))
            return

        if not receiver_id:
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '接收者ID不能为空'
            }))
            return

        try:
            # 保存消息到数据库
            message = await self.save_private_message(receiver_id, content)

            if not message:
                await self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '发送失败：用户不存在或无权限'
                }))
                return

            # 构建消息数据
            message_data = {
                'type': 'private_message',
                'message_id': message.id,
                'sender_id': self.user.id,
                'sender_name': self.user.username,
                'sender_avatar': await self.get_avatar_url_async(self.user),
                'content': content,
                'created_at': message.created_at.isoformat(),
                'is_own': False  # 对接收者来说不是自己的消息
            }

            # 发送给接收者
            await self.channel_layer.group_send(
                f"user_{receiver_id}",
                {
                    'type': 'chat_message',
                    'message': message_data
                }
            )

            # 同时发送给自己（用于确认发送成功）
            message_data['is_own'] = True  # 对自己来说是自己发送的消息
            await self.channel_layer.group_send(
                self.user_channel,
                {
                    'type': 'chat_message',
                    'message': message_data
                }
            )

            logger.info(f"私聊消息发送成功: {self.user.id} -> {receiver_id}")

        except Exception as e:
            logger.error(f"处理私聊消息时发生错误: {e}")
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '发送失败，请重试'
            }))

    async def handle_group_message(self, data):
        group_id = data.get('group_id')
        content = data.get('content', '').strip()

        if not content:
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '消息内容不能为空'
            }))
            return

        if not group_id:
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '群组ID不能为空'
            }))
            return

        try:
            # 检查用户是否在群组中
            if not await self.is_user_in_group(self.user.id, group_id):
                await self.send(text_data=json.dumps({
                    'type': 'error',
                    'message': '您不在该群组中，无法发送消息'
                }))
                return

            # 保存消息到数据库
            message = await self.save_group_message(group_id, content)

            # 构建消息数据
            message_data = {
                'type': 'group_message',
                'message_id': message.id,
                'group_id': group_id,
                'sender_id': self.user.id,
                'sender_name': self.user.username,
                'sender_avatar': await self.get_avatar_url_async(self.user),
                'content': content,
                'created_at': message.created_at.isoformat(),
                'is_own': False  # 对其他成员来说不是自己的消息
            }

            # 发送给群组所有成员（包括自己）
            await self.channel_layer.group_send(
                f"group_{group_id}",
                {
                    'type': 'chat_message',
                    'message': message_data
                }
            )

            logger.info(f"群聊消息发送成功: 群组 {group_id}, 用户 {self.user.id}")

        except Exception as e:
            logger.error(f"处理群聊消息时发生错误: {e}")
            await self.send(text_data=json.dumps({
                'type': 'error',
                'message': '发送失败，请重试'
            }))

    async def handle_typing(self, data):
        target_type = data.get('target_type')  # 'private' or 'group'
        target_id = data.get('target_id')
        is_typing = data.get('is_typing', False)

        if not target_type or not target_id:
            return

        try:
            if target_type == 'private':
                # 只发送给私聊对象，不发送给自己
                await self.channel_layer.group_send(
                    f"user_{target_id}",
                    {
                        'type': 'typing_indicator',
                        'sender_id': self.user.id,
                        'sender_name': self.user.username,
                        'is_typing': is_typing,
                        'target_type': 'private'
                    }
                )
            elif target_type == 'group':
                # 发送给群组其他成员
                typing_data = {
                    'type': 'typing_indicator',
                    'sender_id': self.user.id,
                    'sender_name': self.user.username,
                    'is_typing': is_typing,
                    'target_type': 'group',
                    'target_id': target_id
                }

                # 发送给群组所有成员（包括自己，前端会过滤）
                await self.channel_layer.group_send(
                    f"group_{target_id}",
                    typing_data
                )

        except Exception as e:
            logger.error(f"处理输入指示时发生错误: {e}")

    async def handle_read_receipt(self, data):
        message_id = data.get('message_id')
        message_type = data.get('message_type')  # 'private' or 'group'

        if not message_id or not message_type:
            return

        try:
            await self.mark_message_as_read(message_id, message_type)

            # 通知发送者消息已读（仅私聊）
            if message_type == 'private':
                message = await self.get_private_message(message_id)
                if message and message.sender.id != self.user.id:
                    await self.channel_layer.group_send(
                        f"user_{message.sender.id}",
                        {
                            'type': 'read_receipt',
                            'message_id': message_id,
                            'reader_id': self.user.id,
                            'reader_name': self.user.username,
                            'message_type': 'private'
                        }
                    )
            elif message_type == 'group':
                # 对于群消息，可以通知发送者有人已读
                message = await self.get_group_message(message_id)
                if message and message.sender.id != self.user.id:
                    await self.channel_layer.group_send(
                        f"user_{message.sender.id}",
                        {
                            'type': 'read_receipt',
                            'message_id': message_id,
                            'reader_id': self.user.id,
                            'reader_name': self.user.username,
                            'message_type': 'group',
                            'group_id': message.group.id
                        }
                    )

        except Exception as e:
            logger.error(f"处理已读回执时发生错误: {e}")

    # WebSocket 事件处理方法
    async def chat_message(self, event):
        """处理聊天消息事件"""
        message = event['message']
        await self.send(text_data=json.dumps(message))

    async def typing_indicator(self, event):
        """处理输入指示事件"""
        await self.send(text_data=json.dumps({
            'type': 'typing',
            'sender_id': event['sender_id'],
            'sender_name': event['sender_name'],
            'is_typing': event['is_typing'],
            'target_type': event.get('target_type', 'private'),
            'target_id': event.get('target_id')
        }))

    async def read_receipt(self, event):
        """处理已读回执事件"""
        await self.send(text_data=json.dumps({
            'type': 'read_receipt',
            'message_id': event['message_id'],
            'reader_id': event['reader_id'],
            'reader_name': event['reader_name'],
            'message_type': event.get('message_type', 'private'),
            'group_id': event.get('group_id')
        }))

    async def user_status(self, event):
        """处理用户状态事件"""
        await self.send(text_data=json.dumps({
            'type': 'user_status',
            'user_id': event['user_id'],
            'username': event['username'],
            'status': event['status']
        }))

    # 数据库操作方法
    @database_sync_to_async
    def get_user_groups(self):
        """获取用户所在的群组"""
        return list(ChatGroup.objects.filter(members=self.user))

    @database_sync_to_async
    def save_private_message(self, receiver_id, content):
        """保存私聊消息"""
        try:
            receiver = User.objects.get(id=receiver_id)
            message = PrivateMessage.objects.create(
                sender=self.user,
                receiver=receiver,
                content=content
            )
            return message
        except User.DoesNotExist:
            logger.error(f"接收者不存在: {receiver_id}")
            return None
        except Exception as e:
            logger.error(f"保存私聊消息失败: {e}")
            return None

    @database_sync_to_async
    def save_group_message(self, group_id, content):
        """保存群聊消息"""
        try:
            group = ChatGroup.objects.get(id=group_id)
            message = GroupMessage.objects.create(
                group=group,
                sender=self.user,
                content=content,
                message_type='text'
            )
            return message
        except ChatGroup.DoesNotExist:
            logger.error(f"群组不存在: {group_id}")
            return None
        except Exception as e:
            logger.error(f"保存群聊消息失败: {e}")
            return None

    @database_sync_to_async
    def mark_message_as_read(self, message_id, message_type):
        """标记消息为已读"""
        try:
            if message_type == 'private':
                message = PrivateMessage.objects.get(id=message_id)
                if message.receiver == self.user:
                    message.is_read = True
                    message.save()
            elif message_type == 'group':
                message = GroupMessage.objects.get(id=message_id)
                MessageReadStatus.objects.get_or_create(
                    message=message,
                    user=self.user
                )
        except (PrivateMessage.DoesNotExist, GroupMessage.DoesNotExist):
            logger.warning(f"消息不存在: {message_id}")
        except Exception as e:
            logger.error(f"标记消息已读失败: {e}")

    @database_sync_to_async
    def get_private_message(self, message_id):
        """获取私聊消息"""
        try:
            return PrivateMessage.objects.get(id=message_id)
        except PrivateMessage.DoesNotExist:
            return None

    @database_sync_to_async
    def get_group_message(self, message_id):
        """获取群聊消息"""
        try:
            return GroupMessage.objects.get(id=message_id)
        except GroupMessage.DoesNotExist:
            return None

    @database_sync_to_async
    def is_user_in_group(self, user_id, group_id):
        """检查用户是否在群组中"""
        try:
            group = ChatGroup.objects.get(id=group_id)
            return group.members.filter(id=user_id).exists()
        except ChatGroup.DoesNotExist:
            return False

    @database_sync_to_async
    def get_avatar_url_async(self, user):
        """异步获取头像URL"""
        return self.get_avatar_url(user)

    def get_avatar_url(self, user):
        """获取头像URL"""
        if hasattr(user, 'avatar') and user.avatar:
            return user.avatar.url
        return '/media/avatars/default-avatar.png'

    async def handle_user_online_status(self, data):
        """处理用户在线状态"""
        user_id = data.get('user_id')
        status = data.get('status')

        # 通知所有在线用户该用户状态变化
        await self.channel_layer.group_send(
            "online_users",
            {
                "type": "user_status",
                "user_id": user_id,
                "username": data.get('username'),
                "status": status
            }
        )

    async def handle_message_delivery(self, data):
        """处理消息送达状态"""
        message_id = data.get('message_id')
        message_type = data.get('message_type')

        # 更新消息状态
        await self.update_message_delivery_status(message_id, message_type)

    @database_sync_to_async
    def update_message_delivery_status(self, message_id, message_type):
        """更新消息送达状态"""
        try:
            if message_type == 'private':
                message = PrivateMessage.objects.get(id=message_id)
                message.is_delivered = True
                message.save()
            elif message_type == 'group':
                # 群消息的送达状态处理
                pass
        except Exception as e:
            logger.error(f"更新消息状态失败: {e}")
